﻿#region - 版 本 注 释 -
/*----------------------------------------------------------------
 * 版权所有 (c) 2024   保留所有权利。
 * CLR版本：4.0.30319.42000
 * 机器名称：DESKTOP-GLJ2Q8J
 * 公司名称：
 * 命名空间：AutoCAD.EntityTool
 * 唯一标识：b893f674-d9d1-4fd6-88a5-6b43f5b1d8e0
 * 文件名：BlockTools
 * 当前用户域：DESKTOP-GLJ2Q8J
 * 
 * 创建者：Guo-79991
 * 电子邮箱：799919859@qq.com
 * 创建时间：2024/7/15 12:05:36
 * 版本：V1.0.0
 *
 * 功能描述(Description):
 * 参考文档(Reference):
 * 数据表(Tables):
 * 作者(Author):Guo
 *
 * ----------------------------------------------------------------
 * 修改人：
 * 时间：
 * 修改说明：
 *
 * 版本：V1.0.1
 *----------------------------------------------------------------*/
#endregion - 版 本 注 释 -

namespace AutoCAD.EntityTools.Jig
{
    /// <summary>
    /// 直线Jig
    /// </summary>
    public class LineJig : EntityJig
    {
        private Point3d _startPoint;
        private Point3d _endPoint;
        private string _prompt;
        private string[] _keywords;

        /// <summary>
        /// 直线Jig构造函数
        /// </summary>
        public LineJig(Point3d startPoint, string prompt, string[] keywords)
            : base(new Line(startPoint, startPoint)) // 初始化直线
        {
            _startPoint = startPoint;
            _prompt = prompt;
            _keywords = keywords;
        }

        protected override SamplerStatus Sampler(JigPrompts prompts)
        {
            var jigOptions = new JigPromptPointOptions(_prompt)
            {
                UserInputControls = UserInputControls.Accept3dCoordinates,
                AppendKeywordsToMessage = false,
                BasePoint = _startPoint,
                UseBasePoint = true
            };

            // 添加关键字
            if (_keywords != null)
            {
                foreach (var keyword in _keywords)
                {
                    jigOptions.Keywords.Add(keyword);
                }
            }

            // 添加空格作为确认关键字
            jigOptions.Keywords.Add(" ");

            var promptResult = prompts.AcquirePoint(jigOptions);

            if (promptResult.Status == PromptStatus.Cancel ||
                promptResult.Status == PromptStatus.Error)
                return SamplerStatus.Cancel;

            if (_endPoint.DistanceTo(promptResult.Value) < Tolerance.Global.EqualPoint)
                return SamplerStatus.NoChange;

            _endPoint = promptResult.Value;
            return SamplerStatus.OK;
        }

        protected override bool Update()
        {
            ((Line)Entity).EndPoint = _endPoint;
            return true;
        }

        /// <summary>
        /// 获取创建的直线实体
        /// </summary>
        public Line GetLine() => (Line)Entity;
    }

    public static class LineCreationExtensions
    {
        /// <summary>
        /// 创建直线（自动添加到模型空间）
        /// </summary>
        public static List<ObjectId> CreateLines(this Document document, short colorIndex = 1)
        {
            return CreateLinesInternal(document, null, null, colorIndex);
        }

        /// <summary>
        /// 创建直线（指定事务和块表记录）
        /// </summary>
        public static List<ObjectId> CreateLines(this Document document, Transaction transaction,
            BlockTableRecord blockTableRecord, short colorIndex = 1, string message = "指定第一个点")
        {
            if (transaction == null) throw new ArgumentNullException(nameof(transaction));
            if (blockTableRecord == null) throw new ArgumentNullException(nameof(blockTableRecord));

            return CreateLinesInternal(document, transaction, blockTableRecord, colorIndex, message);
        }

        private static List<ObjectId> CreateLinesInternal(Document document,
            Transaction transaction, BlockTableRecord blockTableRecord,
            short colorIndex, string message = "指定第一个点")
        {
            var editor = document.Editor;
            var database = document.Database;
            var lines = new List<ObjectId>();

            try
            {
                // 获取起点
                var startPointResult = editor.GetPoint(message);
                if (startPointResult.Status != PromptStatus.OK)
                    return lines;

                var currentPoint = startPointResult.Value;
                var startPoint = currentPoint;

                var isComplete = false;

                while (!isComplete)
                {
                    // 根据已有线段数量确定提示信息和关键字
                    string prompt;
                    string[] keywords;

                    if (lines.Count >= 2)
                    {
                        prompt = "\n指定下一点或 [闭合(C)/放弃(U)]:";
                        keywords = new[] { "C", "U" };
                    }
                    else
                    {
                        prompt = "\n指定下一点或 [放弃(U)]:";
                        keywords = new[] { "U" };
                    }

                    // 创建并运行Jig
                    var lineJig = new LineJig(currentPoint, prompt, keywords);
                    var dragResult = editor.Drag(lineJig);

                    switch (dragResult.Status)
                    {
                        case PromptStatus.OK:
                            var line = lineJig.GetLine();
                            line.ColorIndex = colorIndex;

                            ObjectId lineId;
                            if (transaction != null && blockTableRecord != null)
                            {
                                lineId = line.AddToDatabase(transaction, blockTableRecord);
                            }
                            else
                            {
                                lineId = database.AddEntityToModelSpace(line);
                            }

                            lines.Add(lineId);
                            currentPoint = line.EndPoint;
                            break;

                        case PromptStatus.Keyword:
                            HandleKeyword(dragResult.StringResult, ref lines, ref currentPoint,
                                startPoint, editor, database, transaction, blockTableRecord,
                                colorIndex, ref isComplete);
                            break;

                        case PromptStatus.Cancel:
                            // 取消时删除所有已创建的线段
                            foreach (var id in lines)
                            {
                                id.EraseEntity();
                            }
                            lines.Clear();
                            return lines;

                        default:
                            isComplete = true;
                            break;
                    }
                }
            }
            catch (Exception ex)
            {
                editor.WriteMessage($"\n创建直线时发生错误: {ex.Message}");
                // 发生错误时清理已创建的实体
                CleanupEntities(lines);
                lines.Clear();
            }

            return lines;
        }

        private static void HandleKeyword(string keyword, ref List<ObjectId> lines,
            ref Point3d currentPoint, Point3d startPoint, Editor editor, Database database,
            Transaction transaction, BlockTableRecord blockTableRecord, short colorIndex,
            ref bool isComplete)
        {
            switch (keyword)
            {
                case "U": // 放弃
                    UndoLastLine(ref lines, ref currentPoint, startPoint, editor);
                    break;

                case "C": // 闭合
                    CloseLines(lines, currentPoint, startPoint, database, transaction,
                        blockTableRecord, colorIndex);
                    isComplete = true;
                    break;

                case " ": // 空格确认
                    isComplete = true;
                    break;
            }
        }

        private static void UndoLastLine(ref List<ObjectId> lines, ref Point3d currentPoint,
            Point3d startPoint, Editor editor)
        {
            if (lines.Count == 0)
            {
                // 如果没有线段，重新获取起点
                var pointResult = editor.GetPoint("\n指定第一个点:");
                if (pointResult.Status == PromptStatus.OK)
                {
                    currentPoint = pointResult.Value;
                    startPoint = currentPoint;
                }
            }
            else
            {
                // 删除最后一条线段并更新当前点
                var lastLineId = lines[lines.Count - 1];
                currentPoint = lastLineId.GetLineStartPoint();
                lastLineId.EraseEntity();
                lines.RemoveAt(lines.Count - 1);
            }
        }

        private static void CloseLines(List<ObjectId> lines, Point3d currentPoint,
            Point3d startPoint, Database database, Transaction transaction,
            BlockTableRecord blockTableRecord, short colorIndex)
        {
            if (currentPoint.DistanceTo(startPoint) > Tolerance.Global.EqualPoint)
            {
                var closingLine = new Line(currentPoint, startPoint)
                {
                    ColorIndex = colorIndex
                };

                ObjectId closingLineId;
                if (transaction != null && blockTableRecord != null)
                {
                    closingLineId = closingLine.AddToDatabase(transaction, blockTableRecord);
                }
                else
                {
                    closingLineId = database.AddEntityToModelSpace(closingLine);
                }

                lines.Add(closingLineId);
            }
        }

        private static void CleanupEntities(List<ObjectId> entityIds)
        {
            foreach (var id in entityIds)
            {
                try
                {
                    if (!id.IsErased)
                    {
                        id.EraseEntity();
                    }
                }
                catch
                {
                    // 忽略清理过程中的错误
                }
            }
        }
    }

    // 扩展方法类
    public static class EntityExtensions
    {
        public static ObjectId AddToDatabase(this Entity entity, Transaction transaction, BlockTableRecord blockTableRecord)
        {
            blockTableRecord.AppendEntity(entity);
            transaction.AddNewlyCreatedDBObject(entity, true);
            return entity.ObjectId;
        }

        public static Point3d GetLineStartPoint(this ObjectId lineId)
        {
            using (var line = lineId.Open(OpenMode.ForRead) as Line)
            {
                return line?.StartPoint ?? Point3d.Origin;
            }
        }

        public static void EraseEntity(this ObjectId entityId)
        {
            using (var entity = entityId.Open(OpenMode.ForWrite))
            {
                entity.Erase();
            }
        }
    }
}
